#ifndef __SWARM_TAG_WRAPPER_H__
#define __SWARM_TAG_WRAPPER_H__

#include <iostream>

#include "../support/Threading.hpp"

#include <swarm/Identifiable.h>
#include <swarm/Copyable.h>

template<typename T> struct SwarmTagWrapper {
  enum {
    _SwarmTagWrapper_TPTR_OFFS_swarm_Identifiable = 1,
    _SwarmTagWrapper_TPTR_OFFS_swarm_Copyable = _swarm_TPTR_XOFFS(SwarmTagWrapper, swarm_Identifiable),
    _SwarmTagWrapper_TPTR_COUNT = _swarm_TPTR_XOFFS(SwarmTagWrapper, swarm_Copyable)
  };
  static const swarm_tptr_t TPTRS[_SwarmTagWrapper_TPTR_COUNT];

  const swarm_tptr_t * swarm_tptrs;
  
public:
  static const swarm_Type_t TYPE;
  const T * tInst;
  
  SwarmTagWrapper() = delete;
  SwarmTagWrapper(const T *t) : swarm_tptrs(TPTRS), tInst(t) {}
  
  inline const swarm_Identifiable_i *_cast_toIdentifiable() const
  {return reinterpret_cast<const swarm_Identifiable_i *>(this);}
  inline const swarm_Copyable_i *_cast_toCopyable() const
  {return reinterpret_cast<const swarm_Copyable_i *>(this);}
  inline const swarm_Any_i *_cast_toAny() const
  {return reinterpret_cast<const swarm_Any_i *>(this);}
  
  inline static const SwarmTagWrapper<T> *_cast_fromIdentifiable(const swarm_Identifiable_i *t)
  {return reinterpret_cast<const SwarmTagWrapper<T> *>(t);}
  inline static const SwarmTagWrapper<T> *_cast_fromCopyable(const swarm_Copyable_i *t)
  {return reinterpret_cast<const SwarmTagWrapper<T> *>(t);}
  inline static const SwarmTagWrapper<T> *_cast_fromAny(const swarm_Any_i *t)
  {return reinterpret_cast<const SwarmTagWrapper<T> *>(t);}

  // I don't remember if you can do operator const T &() const or not, but it might help.

private:
  // Technically, vv these vv should be extern "C", but Idunno if you can do that inside
  // a class body.  Maybe friend or something.  Haven't met a compiler where it matters,
  // anyway.
  inline static bool _equals(const swarm_Identifiable_i *a, const swarm_Identifiable_i *b)
  {
    bool res = 
      _cast_fromIdentifiable(a)->tInst->equals(_cast_fromIdentifiable(b)->tInst);
#ifdef DEBUG
    SEQUENTIAL_DUMP1( "getequals SwarmTagWrapper @" << a 
                      << " with sub @" << _cast_fromIdentifiable(a)->tInst
                      << " (t = " << *(_cast_fromIdentifiable(a)->tInst)
                      << ") vs @" << b
                      << " with sub @" << _cast_fromIdentifiable(b)->tInst 
                      << " (t = " << *(_cast_fromIdentifiable(b)->tInst) << ")\n");
    SEQUENTIAL_DUMP1( "res = " << res); 
#endif
    return res;
  }
  inline static unsigned long _getHashCode(const swarm_Identifiable_i *a) 
  {
#ifdef DEBUG
    SEQUENTIAL_DUMP1( "gethash SwarmTagWrapper @" << a 
                      << " with sub @" << _cast_fromIdentifiable(a)->tInst << "\n");
#endif
    return _cast_fromIdentifiable(a)->tInst->hashCode();
  }
  inline static void _copy(const swarm_Copyable_i *a, void *out)
  {
    SwarmTagWrapper<T> *STW = reinterpret_cast<SwarmTagWrapper<T> *>(out);
    // STW->tInst = new T(_cast_fromCopyable(a)->tInst);
    STW->swarm_tptrs = _cast_fromCopyable(a)->swarm_tptrs;
    STW->tInst = _cast_fromCopyable(a)->tInst;
  }
  inline static void _deinit(const swarm_Identifiable_i *) {return;}
};

#define TAGWRAPPER_TYPE SwarmTagWrapper<T>::TYPE
#define _TAGWRAPPER_TPTR_COUNT SwarmTagWrapper<T>::_SwarmTagWrapper_TPTR_COUNT
template<typename T> const swarm_Type_t SwarmTagWrapper<T>::TYPE = 
  swarm_Type_INITIALIZER("SwarmTemplatedTagType", TPTRS, sizeof(SwarmTagWrapper<T>));

template<typename T> const swarm_tptr_t SwarmTagWrapper<T>::TPTRS
[SwarmTagWrapper<T>::_SwarmTagWrapper_TPTR_COUNT] = {
  _swarm_XPRIM_TPTR(TAGWRAPPER, 0)
  _swarm_Identifiable_TPTRS(_equals, _getHashCode, _deinit)
  _swarm_Copyable_TPTRS(_copy, swarm_Copyable_copy_CODELET, _deinit)
};
#undef TAGWRAPPER_TYPE 
#undef _TAGWRAPPER_TPTR_COUNT

#endif // __SWARM_TAG_WRAPPER_H__
